/******************************************************************************
 *  Date:
 *      March 2011
 *
 *  Authors:
 *      Tomasz Jankowski 171073
 *
 *  Puprose:
 *      An academic project on Univercity of technologi in Wroclaw.
 *
 ******************************************************************************/
 
#ifndef LIST_HPP
#define LIST_HPP

#include <cassert>

template<typename T> class List
{
    public:    
        class Node
        {
            public:
                friend class List;
                friend class iterator;
                
                ~Node (void)
                {
                    delete this->data;
                }               
                
            private:
                Node (T* data) :
                    data (data),
                    next (NULL),
                    previous (NULL)
                {
                    // ...
                }
                
                T*    data;
                Node* next;
                Node* previous;
        };
        
        class iterator
        {
            friend class List;
            
            public:
                iterator (void) :
                    node (NULL)
                {
                    // ...
                }
                
                iterator (const iterator& element) :
                    node (element.node)
                {
                    // ...
                }
                
                bool is_valid (void)
                {
                    if (this->node != NULL)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                
                bool operator != (const iterator& element)
                {
                    if (this->node == element.node)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                
                T& operator * (void)
                {
                    assert (this->node != NULL);
                    return *(this->node->data);
                }
                
                T* operator -> (void)
                {
                    assert (this->node != NULL);
                    return this->node->data;
                }
                
                iterator& operator++ (int dummy)
                {
                    this->node = this->node->next;
                    return *this;
                }
                
                iterator& operator= (const iterator& element)
                {
                    this->node = element.node;
                    return *this;
                }
            
            private:
                iterator (Node* node) :
                node (node)
                {
                    // ...
                }
                    
                Node* node;
        };
                   
        List (void) :
            head (NULL),
            tail (NULL),
            nodes_counter (0)
        {
            // ...
        }
        
        ~List (void)
        {
            Node* node (this->head);
            
            while (node != NULL)
            {
                Node* tmp_node (node);
                
                delete tmp_node;
                
                node = node->next;
            }
        }
        
        iterator begin (void)
        {
            return iterator (this->head);
        }
        
        iterator end (void)
        {
            return iterator (NULL);
        }
        
        void push_back (const T& value)
        {
            T*    data (new T (value));
            Node* new_node (new Node (data));
            
            if (this->tail != NULL)
            {
                this->tail->next = new_node;
                new_node->previous = this->tail;
                this->tail = new_node;
            }
            else
            {
                this->head = new_node;
                this->tail = new_node;
            }
            
            this->nodes_counter++;
        }
        
        iterator erase (iterator& element)
        {
            assert (element.node != NULL);
            
            Node* first (element.node->previous);
            Node* second (element.node->next);
            
            if (first = NULL && second == NULL)
            {
                // ...
            }
            else if (first == NULL)
            {
                second->previous = NULL;
            }
            else if (second == NULL)
            {
                first->next = NULL;
            }
            else
            {
                first->next = second;
                second->previous = first;
            }
            
            if (element.node == this->head)
            {
                this->head = second;
            }
            
            if (element.node == this->tail)
            {
                this->tail = first;
            }
            
            delete element.node;
            element.node = second;
            
            this->nodes_counter--;
            
            return iterator (second);
        }
        
        bool empty (void)
        {
            if (nodes_counter == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        
    private:       
        Node*        head;
        Node*        tail;
        unsigned int nodes_counter;
};

#endif // LIST_HPP
